unit HAL;

{$mode objfpc}{$H+}
{$IF DEFINED(DEBUG) or DEFINED(DEBUG_CORE)}
  {$L platform.c-debug.obj}
  {$L claim.c-debug.obj}
  {$L clocks.c-debug.obj}
  {$L xosc.c-debug.obj}
  {$L pll.c-debug.obj}
  {$L watchdog.c-debug.obj}
  {$L irq.c-debug.obj}
  {$L timer.c-debug.obj}
{$ELSE}
  {$L platform.c.obj}
  {$L claim.c.obj}
  {$L clocks.c.obj}
  {$L xosc.c.obj}
  {$L pll.c.obj}
  {$L watchdog.c.obj}
  {$L irq.c.obj}
  {$L timer.c.obj}
{$ENDIF}
{$L boot2_pico.obj}
{$LinkLib gcc-armv6m,static}

interface

uses heapmgr;

type
  TPIN = -1 .. 29;
  TAF = (AFXIP, AFSPI, AFUART, AFI2C, AFPWM, AFSIO, AFPIO0, AFPIO1, AFGPCK, AFUSB, AFNONE = $0F);

  TClock = (CLK_GP0, CLK_GP1, CLK_GP2, CLK_GP3, CLK_REF, CLK_SYS, CLK_PERI, CLK_USB, CLK_ADC, CLK_RTC, CLK_COUNT);

  CHW = class
  private
    class var FInstance: CHW;
    class function GetInstance: CHW; static;

  public
    class property Instance: CHW read GetInstance;
    class procedure Release(O: TObject);

  public
    procedure Init;
    class function GetClock(Index: TClock): DWord;

    class procedure SetAF(Pin: TPIN; AF: TAF);
    class function GetAF(Pin: TPIN): TAF;

    class procedure SetBits(var Reg: DWord; Mask: DWord);
    class procedure ClearBits(var Reg: DWord; Mask: DWord);
    class procedure XorBits(var Reg: DWord; Mask: DWord);
    class procedure Masked(var Reg: DWord; Value: DWord; Mask: DWord);

    class function TickCount: Int64;
    class procedure DelayUS(US: Int64);
    class procedure DelayMS(MS: Integer);

    class function D2S(D: DWord): AnsiString;
  end;

  procedure hard_assertion_failure; public name 'hard_assertion_failure';
  procedure __unhandled_user_irq; public name '__unhandled_user_irq';
  procedure __assert_func; public name '__assert_func';

  function time_us_64: Int64; cdecl; external;
  procedure busy_wait_us(delay_us: Int64); cdecl; external;

implementation

  procedure clocks_init; cdecl; external;
  function clock_get_hz(Index: TClock): DWord; cdecl; external;

  procedure gpio_set_function(Pin: TPIN; Fun: TAF); cdecl; external;
  function gpio_get_function(Pin: TPIN): TAF; cdecl; external;

(*****************************************************************************)
procedure hard_assertion_failure;
begin
  Halt;
end;

procedure __unhandled_user_irq;
begin
  Halt;
end;

procedure __assert_func;
begin
  Halt;
end;

(*****************************************************************************)
class function CHW.GetInstance: CHW;
begin
  if FInstance = nil then FInstance:= CHW.Create;
  Result:= FInstance;
end;

class procedure CHW.Release(O: TObject);
var Temp: TObject;
begin
  Temp:= TObject(O);
  Pointer(O):= nil;
  Temp.Free;
end;

procedure CHW.Init;
const
  RESETS_SAFE_BITS      = %1111111111100110110111111;
  RESETS_PRECLOCK_BITS  = %0001111000100110110111110;
  RESETS_POSTCLOCK_BITS = %1110000111000000000000001;
begin
  SetBits(Resets.reset, RESETS_SAFE_BITS);
  ClearBits(Resets.reset, RESETS_PRECLOCK_BITS);

  while (Resets.reset_done and RESETS_PRECLOCK_BITS) <> RESETS_PRECLOCK_BITS do ;
  clocks_init;

  ClearBits(Resets.reset, RESETS_POSTCLOCK_BITS);
  while (Resets.reset_done and RESETS_POSTCLOCK_BITS) <> RESETS_POSTCLOCK_BITS do ;
end;

class function CHW.GetClock(Index: TClock): DWord;
begin
  Result:= clock_get_hz(Index);
end;

class procedure CHW.SetAF(Pin: TPIN; AF: TAF);
begin
  gpio_set_function(Pin, AF);
end;

class function CHW.GetAF(Pin: TPIN): TAF;
begin
  Result:= gpio_get_function(Pin);
end;

class procedure CHW.SetBits(var Reg: DWord; Mask: DWord);
begin
  PDWord(Pointer(@Reg) + $2000)^:= Mask;
end;

class procedure CHW.ClearBits(var Reg: DWord; Mask: DWord);
begin
  PDWord(Pointer(@Reg) + $3000)^:= Mask;
end;

class procedure CHW.XorBits(var Reg: DWord; Mask: DWord);
begin
  PDWord(Pointer(@Reg) + $1000)^:= Mask;
end;

class procedure CHW.Masked(var Reg: DWord; Value: DWord; Mask: DWord);
begin
  Reg:= (Reg and (not Mask)) or Value;
end;

class function CHW.TickCount: Int64;
begin
  Result:= time_us_64;
end;

class procedure CHW.DelayUS(US: Int64);
begin
  busy_wait_us(US);
end;

class procedure CHW.DelayMS(MS: Integer);
begin
  DelayUS(Int64(MS) * 1000);
end;

class function CHW.D2S(D: DWord): AnsiString;
begin
  Result:= '';
  while (D > 0) do
  begin
    Result:= AnsiChar((D mod 10) + $30) + Result;
    D:= D div 10;
  end;
  if (Length(Result) = 0) then Result:= '0';
end;

initialization
  CHW.Instance.Init;

finalization


end.

